package com.zebra.register;

import cn.hutool.core.util.StrUtil;
import com.zebra.remoting.config.*;
import com.zebra.remoting.protocol.CommandProfile;
import lombok.NonNull;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.script.DefaultRedisScript;
import org.springframework.data.redis.serializer.GenericJackson2JsonRedisSerializer;
import org.springframework.data.redis.support.atomic.RedisAtomicInteger;
import org.springframework.stereotype.Service;

import java.util.Arrays;
import java.util.Comparator;
import java.util.List;
import java.util.stream.Collectors;

/**
 * @Date 2020/12/2 0002
 **/
@Service
@Slf4j
public class ServerRedisService {

    private static final String  TMS_MAP = "ZRA:S:TMS";  //MAP
    private static final String  RAS_MAP  = "ZRA:S:RAS";  //MAP
    private static final String  GWS_MAP = "ZRA:S:GWS";   //MAP
    private static final String  CMDS_MAP = "ZRA:CMDS"; //set

    private RedisAtomicInteger sid;

    private final RedisTemplate<String, Object> redisTemplate;

    private final DefaultRedisScript<Long> serverScript;

    @Autowired
    public ServerRedisService(RedisTemplate<String, Object> redisTemplate, DefaultRedisScript<Long> serverScript){
        this.redisTemplate = redisTemplate;
        this.serverScript = serverScript;
        this.sid = new RedisAtomicInteger("ZRA:SID", redisTemplate.getConnectionFactory());

        if (sid.get() < 100){
            sid.set(100);
        }
    }


    //-----TMS-----添加前需要校验之前是否 有相同服务器---
    public void addTmsServer(@NonNull TmsServerInfo tmsServerInfo){
        List<TmsServerInfo> list = findTmsAll();
        TmsServerInfo oldServer = null == list || list.isEmpty() ? null : list.stream().filter(tsi -> tmsServerInfo.equals(tsi)).findFirst().orElse(null);
        if (null != oldServer){
            removeTms(oldServer.getServerId());
        }
        tmsServerInfo.setServerId(getTmsId());
        updateTms(tmsServerInfo);
    }

    public TmsServerInfo getTmsById(Integer serverId){
        return (TmsServerInfo) redisTemplate.opsForHash().get(TMS_MAP, serverId);
    }

    public List<TmsServerInfo> findTmsAll(){
       List<Object> list = redisTemplate.opsForHash().values(TMS_MAP);
        return list.stream().map(o -> (TmsServerInfo)o).collect(Collectors.toList());
    }

    public List<ServerInfoMessage> findTmsMessage(){
        List<TmsServerInfo> list = findTmsAll();
        return list.stream().map(TmsServerInfo::toServerInfoMessage).collect(Collectors.toList());
    }

    public void updateTms(TmsServerInfo serverInfo){
        redisTemplate.opsForHash().put(TMS_MAP, serverInfo.getServerId(), serverInfo);
    }

    public TmsServerInfo removeTms(int serverId){
        TmsServerInfo tmsServerInfo = getTmsById(serverId);
        if (null == tmsServerInfo){
            return null;
        }
        redisTemplate.opsForHash().delete(TMS_MAP, serverId);

        RegisterConfigInfoManager.getInstance().getRegisterServerInfo().removeRsInfo(ServerType.Tms, tmsServerInfo.getServerId());
        updateRegisterServer(RegisterConfigInfoManager.getInstance().getRegisterServerInfo());
        return tmsServerInfo;
    }


    //-------RAS_LIST-----添加前需要校验之前是否 有相同服务器-----
    public void addRegisterServer(@NonNull RegisterServerInfo serverInfo){
        List<RegisterServerInfo> list = findRegisterALL();
        RegisterServerInfo oldServer = null == list || list.isEmpty() ? null : list.stream().filter(tsi -> serverInfo.getInIP().equals(tsi.getInIP()) && serverInfo.getPort() == tsi.getPort()).findFirst().orElse(null);
        if (oldServer != null){
            removeRegister(oldServer.getServerId());
        }
        redisTemplate.opsForHash().put(RAS_MAP, serverInfo.getServerId(), serverInfo);
        RegisterConfigInfoManager.getInstance().setRegisterServerInfo(serverInfo);
    }

    public void updateRegisterServer(@NonNull RegisterServerInfo serverInfo){
        redisTemplate.opsForHash().put(RAS_MAP, serverInfo.getServerId(), serverInfo);
    }


    public List<RegisterServerInfo> findRegisterALL(){
        List<Object> list = redisTemplate.opsForHash().values(RAS_MAP);
        return list.stream().map(o -> (RegisterServerInfo)o).collect(Collectors.toList());
    }

    public List<RegisterServerInfo> findOtherRA(RegisterServerInfo except){
        List<Object> list = redisTemplate.opsForHash().values(RAS_MAP);
        return list.stream().map(o -> (RegisterServerInfo)o).filter(r -> !r.equals(except)).collect(Collectors.toList());
    }

    public List<RegisterServerInfo> findAllByOrder(RegisterServerInfo except){
        List<Object> list = redisTemplate.opsForHash().values(RAS_MAP);
        return list.stream().map(o -> (RegisterServerInfo)o).sorted(Comparator.comparing(RegisterServerInfo::getServerId)).filter(r -> !r.equals(except)).collect(Collectors.toList());
    }

    public RegisterServerInfo getRegisterBySid(int rsid){
        return (RegisterServerInfo) redisTemplate.opsForHash().get(RAS_MAP, rsid);
    }

    public void removeRegister(int serverId){
        RegisterServerInfo registerServerInfo = getRegisterBySid(serverId);
        if (null == registerServerInfo){
            return;
        }
        redisTemplate.opsForHash().delete(RAS_MAP, serverId);
    }



    //------------GWS_LIST------添加前需要校验之前是否 有相同服务器-------
    public void addGateway(@NonNull GatewayServerInfo serverInfo){
        List<GatewayServerInfo> list = findGwAll();
        GatewayServerInfo oldServer = null == list ? null : list.stream().filter(tsi -> serverInfo.equals(tsi)).findFirst().orElse(null);
        if (null != oldServer){
            removeGw(oldServer.getServerId());
        }
        serverInfo.setServerId(getGwId());
        redisTemplate.opsForHash().put(GWS_MAP, serverInfo.getServerId(), serverInfo);
    }

    public GatewayServerInfo getGwById(Integer serverId){
        return (GatewayServerInfo) redisTemplate.opsForHash().get(GWS_MAP, serverId);
    }

    public List<GatewayServerInfo> findGwAll(){
        List<Object> list = redisTemplate.opsForHash().values(GWS_MAP);
        if (null == list || list.isEmpty()){
            return null;
        }

        return list.stream().map(o -> (GatewayServerInfo)o).collect(Collectors.toList());
    }

    public void updateGateway(@NonNull GatewayServerInfo serverInfo){
        redisTemplate.opsForHash().put(GWS_MAP, serverInfo.getServerId(), serverInfo);
    }

    public void removeGw(int serverId){
        GatewayServerInfo gwServer = getGwById(serverId);
        if (null == gwServer){
            return;
        }
        redisTemplate.opsForHash().delete(GWS_MAP, serverId);

        RegisterConfigInfoManager.getInstance().getRegisterServerInfo().removeRsInfo(ServerType.Gateway, gwServer.getServerId());
        updateRegisterServer(RegisterConfigInfoManager.getInstance().getRegisterServerInfo());

    }


    //----------CMDS_SET ---------------------
    public void addCMDS(List<CommandProfile> cmds){
        if (null == cmds || cmds.isEmpty()){
            return;
        }
        cmds.forEach(cp -> redisTemplate.opsForHash().put(CMDS_MAP, cp.getCmd(), cp));
    }

    public List<CommandProfile> findCMDList(){
        List<Object> list = redisTemplate.opsForHash().values(CMDS_MAP);
        return list.stream().map(o -> (CommandProfile)o).collect(Collectors.toList());
    }

    public List<CommandProfile> findCMDListByServer(TmsServerInfo serverInfo){
        String cmds = serverInfo.getCmds();
        if (StrUtil.isEmpty(cmds)){
            return null;
        }
        int[] cmdInts = StrUtil.splitToInt(cmds, ",");
        List<Object> olist = redisTemplate.opsForHash().multiGet(CMDS_MAP, Arrays.stream(cmdInts).boxed().collect(Collectors.toList()));
        if (null == olist || olist.isEmpty()){
            return null;
        }
        return olist.stream().map(o -> (CommandProfile)o).collect(Collectors.toList());
    }


    //----------GT-ID-----------------------
    public int getRaId(){
        return sid.incrementAndGet();
    }

    public int getTmsId(){
        return sid.incrementAndGet();
    }

    public int getGwId(){
        return sid.incrementAndGet();
    }


    //更新 人数
    private String getSingleServerKey(String serverId, String vfx){
        return StrUtil.format("{}-{}", vfx, serverId);
    }

    public long updateOnlineNumber(@NonNull String serverId, @NonNull String vfx, int num){
        GenericJackson2JsonRedisSerializer redisSerializer = new GenericJackson2JsonRedisSerializer();
        List<String> profileKey = Arrays.asList(new String(redisSerializer.serialize(serverId)), new String(redisSerializer.serialize(getSingleServerKey(serverId, vfx))));
        return redisTemplate.execute(serverScript, profileKey, num);
    }


}
